package com.cxdr.awsips.distribute.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.cxdr.awsips.common.logger.LogFactory;
import com.cxdr.awsips.distribute.bean.Distribution_Link;
import com.cxdr.awsips.distribute.bean.Link_Source;
import com.cxdr.awsips.distribute.bean.Link_Target;
import com.cxdr.awsips.distribute.bean.Protocol;
import com.cxdr.awsips.distribute.bean.StoreModel;
import com.cxdr.awsips.distribute.bean.Target;
import com.cxdr.awsips.distribute.rule.FileNameRule;
import com.cxdr.awsips.distribute.rule.StationRule;
import com.cxdr.awsips.distribute.rule.TimeRule;

/**
 * 链路配置工具栏
 * 
 * @author pugang
 * 
 */
public class LinkConfig {
	private static Logger logger = LogFactory.makeNewLogger(LinkConfig.class);
	private static List<LinkConfig> instances = new ArrayList<LinkConfig>();
	private List<Link_Target> targets = new LinkedList<Link_Target>();
	private List<Link_Source> sources = new LinkedList<Link_Source>();
	private Distribution_Link distribution_Link;
	private Properties globalConfig = new Properties();
	private Document configDoc = null;
	private String configName = null;
	private boolean has_folder = true;
	private String statu = "stop";
	private long keepTime = -1; // -1立即删除
	private String localDir = null;
	private static StoreModel storeModel = StoreModel.valueOf(SystemConfig
			.get("link.store"));

	private LinkConfig(String configFile) throws Exception {
		configName = configFile;
		load();
	}

	public static LinkConfig getNewConfig(String configFile) throws Exception {
		logger.info("加载链路文件" + configFile);
		LinkConfig config = new LinkConfig(configFile);
		instances.add(config);
		return config;
	}

	public static void init() throws Exception {
		String allConfigFile = SystemConfig.get("file.link-config");
		SAXReader reader = new SAXReader();
		instances = new ArrayList<LinkConfig>();
		FileInputStream in = new FileInputStream(System.getProperty("user.dir")
				+ File.separator + allConfigFile);
		Document configDoc = reader.read(new InputStreamReader(in, Charset
				.forName("UTF-8")));
		List globalNodes = configDoc.selectNodes("/links/link-file");
		for (Object node : globalNodes) {
			Element el = (Element) node;
			String file = el.getTextTrim();
			getNewConfig(file);
		}
	}

	public static List<LinkConfig> getAllLink() {
		return instances;
	}

	protected synchronized void load() throws Exception {
		switch (storeModel) {
		case DATABASE:
			_loadFromDB();
			break;
		case XML:
			_loadFormXML();
			break;
		}
	}

	/**
	 * 设置存储模式，如果不支持某种模式则抛出不支持异常
	 * 
	 * @throws Exception
	 */
	public static void setStoreModel(StoreModel model) throws Exception {
		if (model != StoreModel.DATABASE && model != StoreModel.XML) {
			throw new Exception("不支持此模式");
		}
		storeModel = model;
	}

	private void _loadFormXML() throws FileNotFoundException, DocumentException {
		SAXReader reader = new SAXReader();
		// logger.info("默认编码是："+reader.getEncoding());
		try {
			// logger.info("设置编码：UTF8");
			// reader.setEncoding("UTF-8");
			FileInputStream in = new FileInputStream(
					System.getProperty("user.dir") + File.separator
							+ configName);
			configDoc = reader.read(new InputStreamReader(in, Charset
					.forName("UTF-8")));
			_loadGlobalXML();
			_loadSourceXML();
			_loadTargetXML();
			configDoc = null;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			logger.error(configDoc);
			logger.error("找不到文件", e);
			throw e;
		} catch (DocumentException e) {
			e.printStackTrace();
			logger.error(configDoc);
			logger.error("文件错误", e);
			throw e;
		}
	}

	/**
	 * 加载全局配置
	 */
	private void _loadGlobalXML() {
		// 配置全局设置
		if (configDoc == null) {
			return;
		}
		List globalNodes = configDoc
				.selectNodes("/link-config/global/property");
		for (Object obj : globalNodes) {
			Element el = (Element) obj;
			String name = el.attribute("name").getValue().toUpperCase();
			String value = el.getTextTrim();
			if (!value.isEmpty()) {
				globalConfig.setProperty(name.toUpperCase(), value);
			}
		}
		Node name_node = configDoc.selectSingleNode("/link-config/name");
		String name = name_node.getText();
		this.configName = name;
		Node keep_node = configDoc.selectSingleNode("/link-config/keep_date");
		String keep_date = keep_node.getText();
		try {
			int hours = Integer.parseInt(keep_date);
			if (hours > 0) {
				this.keepTime = TimeUnit.HOURS.toMillis(hours);
			}
		} catch (NumberFormatException nfe) {
			logger.error("key date 有非法字符！", nfe);
		}
		Node has_folder_node = configDoc
				.selectSingleNode("/link-config/has_folder");
		String has_folder = has_folder_node.getText();
		if ("false".equalsIgnoreCase(has_folder)) {
			this.has_folder = false;
		}
	}

	/**
	 * 加载目标配置
	 */
	private void _loadTargetXML() {
		if (configDoc == null) {
			return;
		}
		// 配置目标全局设置
		Properties targetGlobal = new Properties();
		List globalNodes = configDoc
				.selectNodes("/link-config/targets/global/property");
		for (Object obj : globalNodes) {
			Element el = (Element) obj;
			String name = el.attribute("name").getValue().toUpperCase();
			String value = el.getTextTrim();
			if (!value.isEmpty()) {
				targetGlobal.setProperty(name.toUpperCase(), value);
			}
		}
		for (Object key : globalConfig.keySet()) {
			if (!targetGlobal.containsKey(key)) {
				targetGlobal.put(key, globalConfig.get(key));
			}
		}
		// 配置单独结点
		List nodes = configDoc.selectNodes("/link-config/targets/target");
		for (Object obj : nodes) {
			Element el = (Element) obj;
			List els = el.elements();
			Link_Target target = new Link_Target();
			if (targetGlobal.getProperty("USERNAME") != null) {
				target.setUser_name(targetGlobal.getProperty("USERNAME"));
			}
			if (targetGlobal.getProperty("PASSWORD") != null) {
				target.setPass(targetGlobal.getProperty("PASSWORD"));
			}
			if (targetGlobal.getProperty("PATH") != null) {
				target.setFolder(targetGlobal.getProperty("PATH"));
			}
			if (targetGlobal.getProperty("IP") != null) {
				target.setIp(targetGlobal.getProperty("IP"));
			}
			if (targetGlobal.getProperty("PROTOCOL") != null) {
				target.setProtocol(Protocol.valueOf(targetGlobal
						.getProperty("PROTOCOL")));
			}
			for (Object o : els) {
				Element cel = (Element) o;
				String name = cel.getQualifiedName();
				String text = cel.getTextTrim();
				if (name.equalsIgnoreCase("IP")) {
					target.setIp(text);
				}
				if (name.equalsIgnoreCase("path")) {
					target.setFolder(text);
				}
				if (name.equalsIgnoreCase("ID")) {
					target.setId(text);
				}
				if (name.equalsIgnoreCase("username")) {
					target.setUser_name(text);
				}
				if (name.equalsIgnoreCase("password")) {
					target.setPass(text);
				}
				if (name.equalsIgnoreCase("PROTOCOL")) {
					for (Protocol p : Protocol.values()) {
						if (p.name().equalsIgnoreCase(text)) {
							target.setProtocol(p);
						}
					}
				}

				if (name.equalsIgnoreCase("tact_filename")) {
					target.addFileNameRule(getFileNameRule(cel));
				}
				if (name.equalsIgnoreCase("tact_time")) {
					target.addTimeRule(getTimeRule(cel));
				}
				if (name.equalsIgnoreCase("tact_station")) {
					target.addStationRules(getStationRule(cel));
				}
			}
			logger.info("添加目标：" + target);
			targets.add(target);
		}
	}

	private FileNameRule getFileNameRule(Element cel) {
		Node node_id = cel.selectSingleNode("./id");
		String id = node_id.getText();
		Node node_filter_type = cel.selectSingleNode("./filter_type");
		String filter_type = node_filter_type.getText();
		Node node_reg = cel.selectSingleNode("./reg");
		String reg = node_reg.getText();
		return new FileNameRule(id, filter_type, reg);
	}

	private TimeRule getTimeRule(Element cel) {
		Node node_id = cel.selectSingleNode("./id");
		String id = node_id.getText();
		Node node_filter_type = cel.selectSingleNode("./filter_type");
		String filter_type = node_filter_type.getText();
		Node node_begin_time = cel.selectSingleNode("./begin_time");
		String begin_time = node_begin_time.getText();
		Node node_end_time = cel.selectSingleNode("./end_time");
		String end_time = node_end_time.getText();
		return new TimeRule(id, filter_type, begin_time, end_time);
	}

	private StationRule getStationRule(Element cel) {
		Node node_id = cel.selectSingleNode("./id");
		String id = node_id.getText();
		Node node_filter_type = cel.selectSingleNode("./filter_type");
		String filter_type = node_filter_type.getText();
		Node node_station = cel.selectSingleNode("./station_id");
		String station = node_station.getText();
		return new StationRule(id, filter_type, station);
	}

	/**
	 * 加载目标配置
	 */
	private void _loadSourceXML() {
		if (configDoc == null) {
			return;
		}
		// 配置源全局设置
		Properties sourceGlobal = new Properties();
		List globalNodes = configDoc
				.selectNodes("/link-config/sources/global/property");
		for (Object obj : globalNodes) {
			Element el = (Element) obj;
			String name = el.attribute("name").getValue().toUpperCase();
			String value = el.getTextTrim();
			if (!value.isEmpty()) {
				sourceGlobal.setProperty(name.toUpperCase(), value);
			}
		}
		for (Object key : globalConfig.keySet()) {
			if (!sourceGlobal.containsKey(key)) {
				sourceGlobal.put(key, globalConfig.get(key));
			}
		}
		// 配置单独结点
		List nodes = configDoc.selectNodes("/link-config/sources/target");
		for (Object obj : nodes) {
			Element el = (Element) obj;
			List els = el.elements();
			Link_Source source = new Link_Source();
			if (sourceGlobal.getProperty("USERNAME") != null) {
				source.setUser_name(sourceGlobal.getProperty("USERNAME"));
			}
			if (sourceGlobal.getProperty("PASSWORD") != null) {
				source.setPass(sourceGlobal.getProperty("PASSWORD"));
			}
			if (sourceGlobal.getProperty("PATH") != null) {
				source.setFolder(sourceGlobal.getProperty("PATH"));
			}
			if (sourceGlobal.getProperty("IP") != null) {
				source.setIp(sourceGlobal.getProperty("IP"));
			}
			if (sourceGlobal.getProperty("PROTOCOL") != null) {
				source.setProtocol(Protocol.valueOf(sourceGlobal
						.getProperty("PROTOCOL")));
			}
			for (Object o : els) {
				Element cel = (Element) o;
				String name = cel.getQualifiedName();
				String text = cel.getTextTrim();
				if (name.equalsIgnoreCase("IP")) {
					source.setIp(text);
				}
				if (name.equalsIgnoreCase("path")) {
					source.setFolder(text);
				}
				if (name.equalsIgnoreCase("ID")) {
					source.setId(text);
				}
				if (name.equalsIgnoreCase("username")) {
					source.setUser_name(text);
				}
				if (name.equalsIgnoreCase("password")) {
					source.setPass(text);
				}
				if (name.equalsIgnoreCase("backpath")) {
					source.setBackpath(text);
				}
				if (name.equalsIgnoreCase("protocol")) {
					for (Protocol p : Protocol.values()) {
						if (p.name().equalsIgnoreCase(text)) {
							source.setProtocol(p);
						}
					}
				}
			}
			logger.info("添加源：" + source);
			sources.add(source);
		}
	}

	private void _loadFromDB() {

	}

	public List<Link_Source> getSources() {
		return sources;
	}

	public void setSources(List<Link_Source> sources) {
		this.sources = sources;
	}

	public List<Link_Target> getTargets() {
		return targets;
	}

	public void setTargets(List<Link_Target> targets) {
		this.targets = targets;
	}

	public static StoreModel getStoreModel() {
		return storeModel;
	}

	public int getTargetSize() {
		return targets.size();
	}

	public String getLocalDir() {
		if (localDir != null && !StringUtils.isBlank(localDir)) {
			return localDir;
		}
		StringBuilder path = new StringBuilder(System.getProperty("user.dir"))
				.append(File.separator);
		path.append("cached").append(File.separator);
		for (Target source : sources) {
			path.append(source.getId());
		}
		path.append("-");
		for (Link_Target target : targets) {
			path.append(target.getId());
		}
		Date current = new Date();
		//删除上一个缓存目录
		try {
			String last_hour_dir_str = path.toString()
					+ "-"
					+ DateFormatUtils.format(DateUtils.addDays(current, -1),
							"yyyy-MM-dd_HH");
			File last_hour_dir = new File(last_hour_dir_str);
			if (last_hour_dir.isDirectory()) {
				last_hour_dir.delete();
			}
		} catch (Exception e) {

		}
		path.append("-").append(
				DateFormatUtils.format(current, "yyyy-MM-dd_HH"));
		return path.toString();
	}

	public void setLocalDir(String localDir) {
		this.localDir = localDir;
	}

	public long getKeepTime() {
		return this.keepTime;
	}

	public boolean isSub() {
		return distribution_Link.getHas_folder().equals("true");
	}

	public void setSub(boolean sub) {
		distribution_Link.setHas_folder(sub ? "true" : "false");
	}

	public static void main(String args[]) throws Exception {
		SystemConfig.load();
		LinkConfig.init();
		LinkConfig linkConfig = LinkConfig.getAllLink().get(0);
		for (Link_Target t : linkConfig.getTargets()) {
			for (FileNameRule r : t.getFileNameRules()) {
				System.out.println(r.getId());
			}
			System.out.println("------------------------------------");
			for (TimeRule r : t.getTimeRules()) {
				System.out.println(r.getEnd_time());
			}
			System.out.println("------------------------------------");
			for (StationRule r : t.getStationRules()) {
				System.out.println(r.getId());
			}
		}
		// for(Target t: LinkConfig.getSources()){
		// System.out.println(t.getID());
		// System.out.println(t.getPath());
		// System.out.println(t.getProtocol());
		// System.out.println(t.getUsername());
		// System.out.println(t.getIp());
		// System.out.println("---------------------");
		// }
		// Protocol.values();
		// System.out.println(DateFormatUtils.format(new Date(),
		// "yyyy-mm-dd_HH"));
	}

	public String getLinkName() {
		return configName;
	}

	public void setConfigName(String configName) {
		this.configName = configName;
	}

	public boolean isHas_folder() {
		return has_folder;
	}

	public void setHas_folder(boolean has_folder) {
		this.has_folder = has_folder;
	}

	public void setKeepTime(long keepTime) {
		this.keepTime = keepTime;
	}

	public String getStatu() {
		return statu;
	}

	public void setStatu(String statu) {
		this.statu = statu;
	}

	// private void config

}
